

#include "simple_filter.h"
#include <cstddef>
#include <cstdio>
#include <cstring>

extern "C" {

    #include <libavfilter/avfilter.h>
    #include <libavutil/rational.h>
    #include <libavutil/pixfmt.h>
    #include <libavutil/opt.h>
    #include <libavutil/mem.h>
    #include <libavutil/error.h>
    #include <libavutil/frame.h>

}

int CreateFilter(SimpleFilter * simple_filter, AVCodecContext *codec_ctx, const std::string & desc)
{
    {
        simple_filter->m_buffer_filter_ctx = NULL;
        simple_filter->m_sinker_filter_ctx = NULL;
        simple_filter->m_filter_graph      = NULL;
    }

    int result = 0;

    const AVFilter * buffer_filter = avfilter_get_by_name("buffer");
    const AVFilter * sinker_filter = avfilter_get_by_name("buffersink");

    AVFilterInOut * outputs = avfilter_inout_alloc();
    AVFilterInOut * inputs  = avfilter_inout_alloc();

    
    // AVRational time_base = (AVRational){1, 30};

    enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};

    do 
    {
        simple_filter->m_filter_graph = avfilter_graph_alloc();

        char buffer[1024];
        memset(buffer, 0, sizeof(buffer));
        // 这里需要调整
        snprintf(buffer, sizeof(buffer), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", 
            codec_ctx->width, codec_ctx->height,
            codec_ctx->pix_fmt,
            codec_ctx->time_base.num,codec_ctx->time_base.den,
            codec_ctx->sample_aspect_ratio.num, codec_ctx->sample_aspect_ratio.den);

        result = avfilter_graph_create_filter(&simple_filter->m_buffer_filter_ctx, buffer_filter, "in", buffer, NULL, simple_filter->m_filter_graph);
        if (result < 0)
        {
            result = -1;
            std::cout << "Error: avfilter graph create filter failed in" << std::endl;
            break;
        }
        result = avfilter_graph_create_filter(&simple_filter->m_sinker_filter_ctx, sinker_filter, "out", NULL, NULL, simple_filter->m_filter_graph);
        if (result < 0)
        {
            result = -1;
            std::cout << "Error: avfilter graph create filter failed out" << std::endl;
            break;
        }
        result = av_opt_set_int_list(simple_filter->m_sinker_filter_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);

        if (result)
        {
            result = -1;
            std::cout << "Error: av opt set int list failed" << std::endl;
            break;
        }
        outputs->name = av_strdup("in");
        outputs->filter_ctx = simple_filter->m_buffer_filter_ctx;
        outputs->pad_idx    = 0;
        outputs->next       = NULL;

        inputs->name = av_strdup("out");
        inputs->filter_ctx = simple_filter->m_sinker_filter_ctx;
        inputs->pad_idx    = 0;
        inputs->next       = NULL;

        result = avfilter_graph_parse_ptr(simple_filter->m_filter_graph, desc.c_str(), &inputs, &outputs, NULL);
        if (result < 0)
        {
            result = -1;
            std::cout << "Error: avfilter graph parse ptr code : " << result << std::endl;
            break;
        }
        result = avfilter_graph_config(simple_filter->m_filter_graph, NULL);
        if (result < 0)
        {
            result = -1;
            std::cout << "Error: avfilter graph config" << std::endl;
            break;
        }

    } while (0);

    if (result >= 0)
    {
        std::cout << "result : " << result << std::endl;

        simple_filter->m_input_frame = av_frame_alloc();
        simple_filter->m_output_frame = av_frame_alloc();

        simple_filter->m_input_frame->width = codec_ctx->width;
        simple_filter->m_input_frame->height = codec_ctx->height;
        simple_filter->m_input_frame->format = (AVPixelFormat)AV_PIX_FMT_YUV420P;

        result = av_frame_get_buffer(simple_filter->m_input_frame, 0);
        if (result < 0)
        {
            std::cout << "avframe get buffer" << std::endl;
        }
        result = av_frame_make_writable(simple_filter->m_input_frame);
        if (result < 0)
        {
            std::cout << "avframe make writable" << std::endl;
        }
    }

    return result;
}

int ProcessFrame(SimpleFilter *filter_content)
{
    int result = 0;

    return result;
}